package taskmaster.auth;

import cgi.db.OracleConnect;

import java.sql.Connection;
import java.util.Date;
import java.util.Hashtable;
//import javax.servlet.http.HttpSessionBindingEvent;

/**
 * taskmaster.auth.User
 * Scope: session
 * <p/>
 * Instantiated for each user upon login.
 * <p/>
 * publically readable, but protected from editing by anyone outside the auth package.
 */
public class User
{
    private String username = null;
    private String password = null;
    private Hashtable roles = null;
    private Date loginDate = null;
    private Connection con = null;

    private boolean isSessionBound = false;
    private String databaseLogicalName;

    /**
     * Instantiation of User, but User isn't logged in until username is set.
     * <p/>
     * And don't forget to setRoles for this user
     */
    public User()
    {
        this.loginDate = new Date();
    }

    /**
     * logout by setting all vars in this class to null, (as they were upon instantiation)
     */
    public void logout()
    {

        this.username = null;
        this.roles = null;
        this.loginDate = null;
        try
        {
            if (this.con != null && !this.con.isClosed())
            {
                this.con.close();
            }
        } catch (Exception e)
        {
            System.err.println("(ignorable) Exception in taskmaster.auth.User:logout: " + e);
        }
        this.con = null;
        System.err.println("Logout issued and completed.");
    }

    /**
     * instantiation with username.
     * <p/>
     * Must also setRoles for this user to have any write access.
     */
    protected User(String username, String password) throws Exception
    {
        this.loginDate = new Date();
        this.setUsername(username, password);
    }

    /**
     * returns true if this user is logged in, obviously!
     */
    public boolean isLoggedIn()
    {
        return (this.username == null) ? false : true;
    }

    /**
     * defines this user's username; called on instantiation if username is sent as param
     */
    protected void setUsername(String username, String password) throws Exception
    {
        if (username == null || this.username != null)
        {
            throw new Exception("taskmaster.auth.User: username already set or passed username param is null");
        }
        this.username = username;
        this.password = password;
    }

    /**
     * simply returns the username, or null if its not set (would be tough)
     */
    public String getUsername()
    {
        if (this.username == null)
        {
            throw new IllegalStateException("taskmaster.auth.User:getUsername Cannot get username for not logged in user");
        }
        return this.username;
    }

    /**
     * simply returns the password for this user.  This is unencrypted; just plain text.  used for storing cookies for persistent logon
     */
    public String getPassword()
    {
        if (this.password == null)
        {
            throw new IllegalStateException("taskmaster.auth.User:getPassword Cannot get password for not logged in user");
        }
        return this.password;
    }

    /**
     * checks roleId hash of this user for this roleId.
     * <p/>
     * Use taskmaster.util.LookupRole to map the roleId to the role name
     * returns string of null if not in group, 1 for admin access, 0 for write but no admin access
     */
    public String isInRole(int roleId) throws Exception
    {
        return this.isInRole(String.valueOf(roleId));
    }

    /**
     * same as inInRole that takes an int, except it takes the roleId as a String.
     * Only a bit of repeat...
     */
    public String isInRole(String roleId)
    {
        if (this.username == null)
        {
            throw new IllegalStateException("taskmaster.auth.User: Cannot get roles for not logged in user");
        }
        if (roles == null)
        {
            return null;
        }
        return (String) this.roles.get(roleId);
    }

    /**
     * Takes a complete hashtable of all Role objects for this user.
     * <p/>
     * As a result of the null check, once rolls are set for this session,
     * they cannot be reset.  The user will have to logout and back in to see changes.
     */
    protected void setRoles(Hashtable roles)
    {
        if (this.username == null)
        {
            throw new IllegalStateException("taskmaster.auth.User: Cannot get roles for not logged in user");
        }
        if (this.roles != null)
        {
            throw new IllegalStateException("taskmaster.auth.User: internal roles hash already set.  Cannot be overwritten");
        }
        this.roles = roles;
    }

    /**
     * returns the Hashtable used as role storage
     */

    public Hashtable getAllRoles()
    {
        if (this.username == null)
        {
            throw new IllegalStateException("taskmaster.auth.User:getAllRoles Cannot get roles for not logged in user");
        }
        return roles;
    }

    /**
     * Sets the connection to the db for this user for this session
     * <p/>
     * Throws Exception if new connection isn't open already or if the user's existing connection is open already
     */
    public void setConnection(Connection con, String databaseLogicalName) throws Exception
    {
        if (con.isClosed())
        {
            throw new Exception("Exception in taskmaster.auth.User:setConnection:  Param connection to db seems to be closed");
        }
        if (this.con == null || this.con.isClosed())
        {
            this.con = con;
            this.databaseLogicalName = databaseLogicalName;
        } else
        {
            throw new Exception("Exception in taskmaster.auth.User:setConnection:  Connection already open for this user");
        }
    }

    /**
     * returns the connection to the db for this user
     */
    public Connection getConnection()
    {
        return this.con;
    }

    public String getUserNameDatabaseString()
    {
        return username + "@" + databaseLogicalName;
    }

    /**
     * returns a Date of when the user logged in.  May be useful for something...
     */
    public Date getLoginDate() throws Exception
    {
        if (this.username == null)
        {
            throw new Exception("taskmaster.auth.User:getLoginDate Cannot get login date for not logged in user");
        }
        return this.loginDate;
    }

    /**
     * closes the user's connection and gets another to put in its place.
     */
    public void releaseDB()
    {
        try
        {
            if (this.con != null && !this.con.isClosed())
            {
                this.con.close();
            }
            this.con = OracleConnect.getConnection(this.username, this.password);
        } catch (Exception e)
        {
            System.err.println("(ignorable) Exception in taskmaster.auth.User:logout: " + e);
        }
    }

    /**
     * true if this object is bound to the tomcat session manager; false otherwise
     */
    public boolean getIsSessionBound()
    {
        return this.isSessionBound;
    }

    /** implements the HttpSessionBindingListener interface.
     * <BR>allows this object to be bound to tomcat's session manager
     */
/*	public void valueBound(HttpSessionBindingEvent event) {
		System.err.println("Just bound the session!!!");
		this.isSessionBound = true;
	}

	/**implements the HttpSessionBindingListener interface.
	 * <BR>allows this object to be bound to tomcat's session manager
	 */
    /*
        public void valueUnbound(HttpSessionBindingEvent event) {
            try {
                //System.err.println("Before unbound close, db connection closed?: "+ this.con.isClosed());
                this.isSessionBound = false;
                this.logout();
            } catch (Exception e) {
                System.err.println("Exception taskmaster.auth.User:valueUnbound: "+ e);
                this.isSessionBound = false;
                this.logout();
            }
        }
    */

}
